#include <mach/mach.h>
#include <mach-o/dyld.h>
#include <string.h>
#include <unistd.h>
#include <os/log.h>
#include <mach-o/loader.h>
#include <mach/mach_vm.h>

// Boyer-Moore 搜索算法
void *search_bytes(const uint8_t *haystack, size_t haystack_len,
                   const uint8_t *needle, size_t needle_len)
{
    if (needle_len == 0)
        return (void *)haystack;
    if (haystack_len < needle_len)
        return NULL;
    int n = needle_len - 1;

    // 构建坏字符表
    size_t bad_char[256];
    for (size_t i = 0; i < 256; i++)
    {
        bad_char[i] = needle_len;
    }
    for (size_t i = 0; i < n; i++)
    {
        bad_char[needle[i]] = n - i;
    }

    // 搜索
    size_t offset = 0;
    while (offset <= haystack_len - needle_len)
    {
        int j = n;
        while (j >= 0 && needle[j] == haystack[offset + j])
        {
            j--;
        }
        if (j < 0)
        {
            return (void *)(haystack + offset);
        }
        offset += bad_char[haystack[offset + j]];
    }
    return NULL;
}

const uint8_t *text_start;
static uint32_t text_offset;
// 在 text 段中搜索
void *find_bytes_in_text(const uint8_t *target, size_t target_len)
{
    // 获取 mach-o header
    const struct mach_header_64 *header = (const struct mach_header_64 *)_dyld_get_image_header(0);
    const struct load_command *cmd = (const struct load_command *)((uint8_t *)header + sizeof(struct mach_header_64));

    // 遍历加载命令找到 text 段
    for (uint32_t i = 0; i < header->ncmds; i++)
    {
        if (cmd->cmd == LC_SEGMENT_64)
        {
            const struct segment_command_64 *seg = (const struct segment_command_64 *)cmd;
            if (strcmp(seg->segname, "__TEXT") == 0)
            {
                // 遍历 sections
                const struct section_64 *sect = (const struct section_64 *)((uint8_t *)seg + sizeof(struct segment_command_64));
                for (uint32_t j = 0; j < seg->nsects; j++)
                {
                    if (strcmp(sect->sectname, "__text") == 0)
                    {
                        // 在 text section 中搜索
                        text_start = (const uint8_t *)header + sect->offset;
                        text_offset = sect->offset;
                        printf("text_start: %p,%p\n", sect->offset, text_start);
                        return search_bytes(text_start, sect->size, target, target_len);
                    }
                    sect++;
                }
            }
        }
        cmd = (const struct load_command *)((uint8_t *)cmd + cmd->cmdsize);
    }
    return NULL;
}

// extern int loader_C(void *L);
// extern int loader_Croot(void *L);

// 在程序加载时自动执行的构造函数
__attribute__((constructor)) void inject_entry()
{
    os_log_t log = os_log_create("com.example.app", "general");
    os_log(log, "注入库已加载到目标进程。PID: %d", getpid());

    // 计算偏移地址
    const uint8_t needle[] = {0x4A, 0x8B, 0x34, 0x3B, 0x4C, 0x89, 0xF7, 0x31, 0xD2};
    void *ret = find_bytes_in_text(needle, sizeof(needle));
    if (ret == NULL)
    {
        os_log(log, "未找到匹配");
        return;
    }

    mach_vm_address_t target_address = (uint64_t)(ret + *(uint32_t *)(ret - 4) + 0x10);
    os_log(log, "找到匹配: 0x%llx", target_address);
    printf("找到匹配: 0x%llx\n", target_address);
    printf("找到匹配: %p\n", (int)target_address - (int)text_start + (int)text_offset);

    // 写入新值
    // 获取当前任务的端口
    mach_port_t task;
    // uint64_t new_function_value = (uint64_t)loader_C;
    task_for_pid(mach_task_self(), getpid(), &task);
    // kern_return_t write_result = mach_vm_write(task, target_address, (vm_offset_t)&new_function_value, sizeof(new_function_value));
    // if (write_result != KERN_SUCCESS) {
    //     os_log_error(log, "写入失败 (第一次): %s\n", mach_error_string(write_result));
    //     return; // 写入失败，退出
    // }

    // target_address += 8;
    // new_function_value = (uint64_t)loader_Croot;
    // write_result = mach_vm_write(task, target_address, (vm_offset_t)&new_function_value, sizeof(new_function_value));
    // if (write_result != KERN_SUCCESS) {
    //     os_log_error(log, "写入失败 (第二次): %s\n", mach_error_string(write_result));
    //     return;
    // }
    os_log(log, "内存写入成功。");
    getchar();
}

// 编译命令:
// cc -o inject.dylib lapi.c lcode.c ldebug.c ldo.c ldump.c lfunc.c lgc.c llex.c lmem.c lobject.c lopcodes.c lparser.c lstate.c lstring.c ltable.c ltm.c lundump.c lvm.c lzio.c lauxlib.c lbaselib.c ldblib.c liolib.c lmathlib.c loslib.c ltablib.c lstrlib.c loadlib.c linit.c inject_mac.c -shared -DLUA_USE_LINUX -lreadline -arch x86_64 -O2
// gcc main.c -o main
// DYLD_INSERT_LIBRARIES=./inject.so ./main

// 0f 1f 00 45 33 c0 48 8b d0 48 8b cb

// 4A 8B 34 3B 4C 89 F7 31 D2
// cc -g -shared -arch x86_64 -O2 inject_test.c -o /Users/zhang/Library/Application\ Support/Steam/steamapps/common/Don\'t\ Starve\ Together/dontstarve_steam_inject.dylib